#include "MIKE_ZHOU_STM32_HAL.h"
#include <string.h>

#ifdef HAL_FLASH_MODULE_ENABLED
void MZ_STM32_HAL_FLASH_Test(void)
{
	uint32_t add = 0x08010000;        //定义写入数据的地址
	uint32_t error = 0;
	uint64_t dat = 0x0123456776543210;//要写入的数据，必须得是双字64bit
	uint64_t readDat = 0 ;
	FLASH_EraseInitTypeDef flashDat;          //定义一个结构体变量，里面有擦除操作需要定义的变量
	
	HAL_FLASH_Unlock(); 
	/*	//第二步：解锁                        
	flashDat.TypeErase = FLASH_TYPEERASE_PAGES;         //擦除类型是“Page Erase” 仅删除页面 另外一个参数是全部删除
	flashDat.Page = (uint32_t)((add-0x08000000)/2048);            //擦除地址对应的页
	flashDat.NbPages = 1;                               //一次性擦除1页,可以是任意页
	flashDat.Banks=1;
	*/
	HAL_FLASHEx_Erase(&flashDat,&error);            //第三步：参数写好后调用擦除函数
	
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, add, dat);//第四步：写入数据
	HAL_FLASH_Lock();                                      //第五步：上锁
	
	readDat = *(__I uint64_t *)add;	   //读出flash中的数据
	uint32_t readDat1=readDat>>32;
	uint32_t readDat2=readDat&0x00000000FFFFFFFF;
	UNUSED(readDat1);
	UNUSED(readDat2);
	// printf("[INFO] Flash_Test:0x%08x 0x%08x\n",readDat1,readDat2);
}

int MZ_STM32_HAL_FLASH_GetSectorPage(uint32_t addr)
{
	uint8_t sector = 0;

	#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F412Zx) ||\
		defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) 
	if(addr<0x08000000 || addr >= 0x08100000)
	{
		return -1;
	}
	#endif
	
	#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F412Zx) ||\
	defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) 
	if(addr<0x08010000)
	{
		sector = (addr - 0x08000000)/(16*1024);
	}
	else if(addr<0x08020000)
	{
		sector = 4;
	}
	else
	{
		sector = 5+(addr - 0x08020000)/(128*1024);
	}
	#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */
	
	return sector;
}

int MZ_STM32_HAL_FLASH_GetBank(uint32_t addr)
{
	uint8_t bank = 0;
	
	#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F412Zx) ||\
		defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) 
	if(addr<0x08000000 || addr >= 0x08100000)
	{
		return -1;
	}
	#endif
	
	#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) ||\
    defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F410Tx) || defined(STM32F410Cx) ||\
    defined(STM32F410Rx) || defined(STM32F411xE) || defined(STM32F446xx) || defined(STM32F412Zx) ||\
    defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) ||\
    defined(STM32F423xx)
	bank = 1;
	#endif /* STM32F40xxx || STM32F41xxx || STM32F401xx || STM32F410xx || STM32F411xE || STM32F446xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx
			  STM32F413xx || STM32F423xx */
	
	return bank;
}

//byteLength: 0 1 2 3 -> FLASH_Type_Program
uint32_t MZ_STM32_HAL_FLASH_Write(uint32_t addr,void * buf,uint32_t len,uint8_t byteLength)
{
	uint32_t error = 0;
	uint32_t i = 0;
	uint32_t realLen = 0;
	uint32_t byteNum = 0;
	
	FLASH_EraseInitTypeDef flash_dat;          //定义一个结构体变量，里面有擦除操作需要定义的变量	
	HAL_FLASH_Unlock();                                    //第二步：解锁                        
	
	#if defined (STM32F4)
	flash_dat.TypeErase = FLASH_TYPEERASE_SECTORS;         //擦除类型是“Page Erase” 仅删除页面 另外一个参数是全部删除
	flash_dat.Sector =  (uint32_t)MZ_STM32_HAL_FLASH_GetSectorPage(addr);           //擦除地址对应的页
	flash_dat.NbSectors = 1;                               //一次性擦除1页,可以是任意页
	flash_dat.Banks = (uint32_t)MZ_STM32_HAL_FLASH_GetBank(addr);
	flash_dat.VoltageRange = (uint32_t)byteLength;
	#elif defined (STM32L4)
	flash_dat.TypeErase = FLASH_TYPEERASE_PAGES;         //擦除类型是“Page Erase” 仅删除页面 另外一个参数是全部删除
	flash_dat.Page = (uint32_t)MZ_STM32_HAL_FLASH_GetSectorPage(addr);            //擦除地址对应的页
	flash_dat.NbPages = 1;                               //一次性擦除1页,可以是任意页
	flash_dat.Banks = (uint32_t)MZ_STM32_HAL_FLASH_GetBank(addr);
	#endif
	
	HAL_FLASHEx_Erase(&flash_dat,&error);            //第三步：参数写好后调用擦除函数
	FLASH_WaitForLastOperation(0xFFFF); 	
	if(error != 0xFFFFFFFFU)
	{
		HAL_FLASH_Lock(); 
		return byteNum;
	}

	switch(byteLength)
	{
		case FLASH_TYPEPROGRAM_BYTE:
		{
			realLen = len;
			for(i=0;i<realLen;i++)
			{
				if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr+i, ((uint8_t *)buf)[i]))
				{
					break;
				}
				byteNum++;
			}
			break;
		}
		
		case FLASH_TYPEPROGRAM_HALFWORD:
		{
			realLen = len/2;
			for(i=0;i<realLen;i++)
			{
				if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr+(2*i), ((uint16_t *)buf)[i]))
				{
					break;
				}
				byteNum+=2;
			}
			break;
		}
		
		case FLASH_TYPEPROGRAM_WORD:
		{
			realLen = len/4;
			for(i=0;i<realLen;i++)
			{
				if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+(4*i), ((uint32_t *)buf)[i]))
				{
					break;
				}
				byteNum+=4;
			}
			break;
		}
		
		case FLASH_TYPEPROGRAM_DOUBLEWORD:
		{
			realLen = len/8;
			for(i=0;i<realLen;i++)
			{
				if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+(8*i), ((uint64_t *)buf)[i]))
				{
					break;
				}
				byteNum+=8;
			}
			break;
		}
		
		default:break;
	}

	FLASH_WaitForLastOperation(0xFFFF); 
	
	HAL_FLASH_Lock();                                      //第五步：上锁

	return byteNum;
}

#endif
